﻿using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.LoadTesting;

// CustomLoadProfiles.cs
// Blog: http://blogs.msdn.com/yutong/archive/2010/03/15/load-test-plug-in-simulate-multiple-and-repeated-user-load-patterns-step-2-1.aspx
// You can add more custom profiles in this file
namespace CustomLoadProfiles
{
    #region Custom LoadProfile

    // The base class for customized load profile
    // Add different validations as needed
    [Serializable]
    public class CustomLoadProfile : LoadTestStepLoadProfile
    {
        int m_currentUserLoad;
        public CustomLoadProfile()
        {
            m_currentUserLoad = 0;
        }

        public int CurrentUserLoad
        {
            get { return m_currentUserLoad; }
            set { m_currentUserLoad = value; }
        }

        public override int GetLoad(int elaspsedTimeInProfile)
        {
            return 0;
        }

        public override void Validate() { }
    }

    // Custom step up/down - Sin wave simulation
    // y(t) = A * sin(2* PI * f * t / unitTimeInterval)
    // t - time
    // f - number of oscillations occur in an unit time interval
    [Serializable]
    public class LoadTestSinLoadProfile : CustomLoadProfile
    {
        int m_amplitude;
        int m_unitTimeInterval;
        int m_freq;
        public LoadTestSinLoadProfile(int initCount, int amplitude, int unitTmeInterval, int frequency, int stepDuration)
        {
            InitialUserCount = initCount;
            StepDuration = stepDuration;
            m_amplitude = amplitude;
            m_unitTimeInterval = unitTmeInterval;
            m_freq = frequency;
        }

        public override int GetLoad(int elapsedTimeInProfile)
        {
            if (elapsedTimeInProfile % StepDuration == 0)
            {
                CurrentUserLoad = CalculateUserLoad(elapsedTimeInProfile);
            }

            return (int)Math.Max(CurrentUserLoad, MinUserCount);
        }

        // If you are familiar with Sin curves, you can modify the formula to calculate user load
        int CalculateUserLoad(int elapsedTimeInProfile)
        {
            double userLoad = 0;
            userLoad = Math.Sin(2 * Math.PI * m_freq * elapsedTimeInProfile / m_unitTimeInterval) * m_amplitude;
            userLoad = InitialUserCount + userLoad;

            return (Int32)(userLoad);
        }
    }

    // Custom step down - linear
    [Serializable]
    public class LoadTestStepDownLoadProfile : CustomLoadProfile
    {
        public LoadTestStepDownLoadProfile(int initCount, int minCount, int maxCount, int stepCount, int stepDuration)
        {
            InitialUserCount = initCount;
            StepUserCount = stepCount;
            StepDuration = stepDuration;
            MinUserCount = minCount;
            MaxUserCount = maxCount;
            CurrentUserLoad = initCount;
        }

        public override int GetLoad(int elapsedTimeInProfile)
        {
            if (elapsedTimeInProfile % StepDuration == 0)
            {
                CurrentUserLoad -= StepUserCount;
            }

            return (int)Math.Max(CurrentUserLoad, MinUserCount);
        }
    }

    #endregion

    #region CustomLoadProfile Warpper Classes
    // The base class (wrapper) for a customized load profile
    public abstract class LoadProfileWrapper
    {
        bool m_inUse;
        int m_duration;  // How long this pattern will be simulated 

        public int Duration
        {
            get { return m_duration; }
            set { m_duration = value; }
        }

        public bool InUse
        {
            get { return m_inUse; }
            set { m_inUse = value; }
        }

        public abstract LoadTestLoadProfile Profile
        {
            get;
            set;
        }

        public virtual void UpdateProfileStatus(bool inUse, int currentUserLoad)
        {
            InUse = inUse;
        }
    }

    public class CustomLoadWrapper : LoadProfileWrapper
    {
        LoadTestLoadProfile m_profile;
        public CustomLoadWrapper(int patternDuration)
        {
            m_profile = new LoadTestConstantLoadProfile(); // instantiate it as an const load file
            InUse = false;
            Duration = patternDuration;
        }

        public override LoadTestLoadProfile Profile
        {
            get { return m_profile; }
            set { m_profile = (LoadTestLoadProfile)value; }
        }

        public override void UpdateProfileStatus(bool inUse, int currentUserCount)
        {
            InUse = inUse;
            if (m_profile is CustomLoadProfile)
            {
                ((CustomLoadProfile)m_profile).CurrentUserLoad = currentUserCount;
            }
        }
    }

    // The const load profile wrapper
    public class ConstLoadWrapper : LoadProfileWrapper
    {
        LoadTestConstantLoadProfile m_profile;
        public ConstLoadWrapper(int userCount, int duration)
        {
            m_profile = new LoadTestConstantLoadProfile();
            m_profile.UserCount = userCount;
            Duration = duration;
        }

        public override LoadTestLoadProfile Profile
        {
            get { return m_profile; }
            set { m_profile = (LoadTestConstantLoadProfile)value; }
        }
    }

    // The goal based load profile wrapper
    public class GoalBasedLoadWrapper : LoadProfileWrapper
    {
        LoadTestGoalBasedLoadProfile m_profile;
        public GoalBasedLoadWrapper(int initialCount, int minCount, int maxCount, int maxIncrement, int maxDecrement, int patternDuration)
        {
            m_profile = new LoadTestGoalBasedLoadProfile();
            m_profile.InitialUserCount = initialCount;
            m_profile.MinUserCount = minCount;
            m_profile.MaxUserCount = maxCount;
            m_profile.MaxUserCountIncrease = maxIncrement;
            m_profile.MaxUserCountDecrease = maxDecrement;
            Duration = patternDuration;
        }

        public void SetCounter(string machine, string category, string counter, string instance, bool stopAdjustingAtGoal)
        {
            m_profile.MachineName = machine;
            m_profile.InstanceName = instance;
            m_profile.CategoryName = category;
            m_profile.CounterName = counter;
            m_profile.StopAdjustingAtGoal = stopAdjustingAtGoal;
        }

        public override LoadTestLoadProfile Profile
        {
            get { return m_profile; }
            set { m_profile = (LoadTestGoalBasedLoadProfile)value; }
        }
    }

    // The step load profile wrapper
    public class StepLoadWrapper : LoadProfileWrapper
    {
        LoadTestStepLoadProfile m_profile;
        public StepLoadWrapper(int initCount, int minCount, int maxCount, int stepCount, int stepDuration, int stepRampTime, int patternDuration)
        {
            m_profile = new LoadTestStepLoadProfile();
            m_profile.InitialUserCount = initCount;
            m_profile.MinUserCount = minCount;
            m_profile.MaxUserCount = maxCount;
            m_profile.StepUserCount = stepCount;
            m_profile.StepDuration = stepDuration;
            m_profile.StepRampTime = stepRampTime;
            InUse = false;
            Duration = patternDuration;
        }

        public override LoadTestLoadProfile Profile
        {
            get { return m_profile; }
            set { m_profile = (LoadTestStepLoadProfile)value; }
        }
    } 


    #endregion
}

